package TDengineDB

import (
	"errors"
	"fmt"
	"strconv"
	"strings"
)

// TDengineRepository 数据刻苦存储
type TDengineRepository struct {
	database       string          //数据库名称
	superTableName string          //超级表名称(创建超级表用)
	client         *TDengineClient //客户端
}

// GetDatabase 获取数据库名
func (t *TDengineRepository) GetDatabase() string {
	return t.database
}

// GetSuperTableName 获取表名称
func (t *TDengineRepository) GetSuperTableName() string{
	return t.superTableName
}

//Add 插入数据(单个)对单个表操作(不能存储带有特殊字符内容如:\n \r \...)
//tableName:表名称   value:1，“A”,123
func (t *TDengineRepository) Add(tableName, value,tags string) (int64,error) {
	return t.AddMany(map[string]*InsertData{
		tableName: {
			Tags: tags,
			Data: []string{value},
		},
	})
}

//AddMany 插入数据(单个或批量)对单个表操作(不能存储带有特殊字符内容如:\n \r \...)
//map[ key:表名称，value:{"Tags":"tag0,tag1...",data:["\"1538548695000, 12.6, 218, 0.33\",""\"1538548695000, 12.6, 218, 0.33\"...]}} ] values 最大长度不能超过 数据库配置值(数据库默认大小62k)
//INSERT INTO d1001 USING METERS TAGS ("Beijng.Chaoyang", 2) VALUES (now, 10.2, 219, 0.32);
//INSERT INTO d1001 VALUES (1538548685000, 10.3, 219, 0.31) (1538548695000, 12.6, 218, 0.33) d1002 VALUES (1538548696800, 12.3, 221, 0.31);
//CREATE TABLE meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupdId int);
func (t *TDengineRepository) AddMany(dataDict map[string]*InsertData) (int64,error) {
	bt := strings.Builder{}
	count := int64(0)
	isStart := false
	for key, val := range dataDict {
		if !isStart {
			bt.WriteString("INSERT INTO ")
			isStart = true
		}
		bt.WriteString(t.database)
		bt.WriteString(".")
		bt.WriteString(key)
		bt.WriteString(" USING ")
		bt.WriteString(t.database)
		bt.WriteString(".")
		bt.WriteString(t.superTableName)
		bt.WriteString(" TAGS (")
		bt.WriteString(val.Tags)
		bt.WriteString(") VALUES ")
		for _, row := range val.Data {
			if !isStart {
				bt.WriteString("INSERT INTO ")
				isStart = true
				bt.WriteString(t.database)
				bt.WriteString(".")
				bt.WriteString(key)
				bt.WriteString(" USING ")
				bt.WriteString(t.database)
				bt.WriteString(".")
				bt.WriteString(t.superTableName)
				bt.WriteString(" TAGS (")
				bt.WriteString(val.Tags)
				bt.WriteString(") VALUES ")
			}
			bt.WriteString("(")
			bt.WriteString(row)
			bt.WriteString(") ")
			if bt.Len() < 50*1024 {
				continue
			}
			bt.WriteString(";")
			sql := bt.String()
			result, err := t.Execute(sql)
			if err != nil {
				return count, err
			}
			if len(result.Data) != 0 {
				count += int64(result.Data[0][0].(float64))
			}
			isStart = false
			bt.Reset()
		}
	}
	if bt.Len() > 0 {
		bt.WriteString(";")
		sql := bt.String()
		result, err := t.Execute(sql)
		if err != nil {
			return count, err
		}
		if len(result.Data) != 0 {
			count += int64(result.Data[0][0].(float64))
		}
	}
	return count, nil
}

//Execute 执行[直接执行sql，可查询，可插入](不能存储带有特殊字符内容如:\n \r \...)
func (t *TDengineRepository) Execute(sqlCmd string) (*ExecuteResult,error) {
	return t.client.Execute(sqlCmd)
}

// QuerySuperTop 根据条件查询超级中的数据
// columns:列名,...（*或""表示全部)
// queryWhere:条件(a='123')；
// topCount: 排序后前多少条；
// sort排序(只支持时间): 0 => 默认,1 => order by ts desc， 2 => order by ts；
// handFn：数据处理函数(非必须)
// ，返回切片字典
func (t *TDengineRepository) QuerySuperTop(columns,queryWhere string,topCount ,sort int) (result *ExecuteResult,err error) {
	result, _, err = t.QuerySuper(columns, queryWhere, 1, topCount, sort, false)
	return result, err
}

// QuerySuperPage 根据条件查询超级中的数据
// columns:列名,...（*或""表示全部）;
// queryWhere:条件(a='123')；
// pageIndex:页数从1开始；
// pageSize:页条数
// sort排序(只支持时间): 0 => 默认,1 => order by ts desc， 2 => order by ts；
// handFn：数据处理函数(非必须)
// ，返回切片字典，数据总数
func (t *TDengineRepository) QuerySuperPage(columns,queryWhere string,pageIndex,pageSize,sort int) (result *ExecuteResult,totalCount int64, err error) {
	return t.QuerySuper(columns, queryWhere, pageIndex, pageSize, sort, true)
}

// QueryCount 查询总个数
// queryWhere:条件(a='123')
func (t *TDengineRepository) QueryCount(queryWhere string) (int64,error) {
	if queryWhere == "" {
		return 0, errors.New(" queryWhere 不允许为空！")
	}
	totalSqlCmd := fmt.Sprint("select count(*) from ", t.database, ".", t.superTableName, " where ", queryWhere, ";")
	executeResult, err := t.Execute(totalSqlCmd)
	if err != nil {
		return 0, err
	}
	if len(executeResult.Data) == 0 {
		return  0,nil
	} else {
		return int64(executeResult.Data[0][0].(float64)),nil
	}
}

// QuerySuper 根据条件查询超级中的数据
// columns:列名,...（*或""表示全部）;
// queryWhere:条件(a='123')；
// pageIndex:页数从1开始；
// pageSize:页条数
// sort排序(只支持时间): 0 => 默认,1 => order by ts desc， 2 => order by ts；
// isCount:是否需要总数
// handFn：数据处理函数(非必须)
// ，返回切片字典，数据总数
func (t *TDengineRepository) QuerySuper(columns,queryWhere string,pageIndex,pageSize,sort int,isTotalCount bool) (result *ExecuteResult,totalCount int64, err error) {
	if queryWhere == "" {
		return nil, 0, errors.New(" queryWhere 不允许为空！")
	}
	if isTotalCount {
		/*查条数*/
		totalSqlCmd := fmt.Sprint("select count(*) from ", t.database, ".", t.superTableName, " where ", queryWhere, ";")
		countRes, err := t.Execute(totalSqlCmd)
		if err != nil {
			return nil, 0, err
		}
		if len(countRes.Data) == 0 {
			totalCount = 0
		} else {
			totalCount = int64(countRes.Data[0][0].(float64))
		}
	} else {
		totalCount = -1
	}
	/*查数据*/
	sqlCmd := strings.Builder{}
	sqlCmd.WriteString("select ")
	if columns == "" {
		sqlCmd.WriteString(" * ")
	} else {
		sqlCmd.WriteString(columns)
		sqlCmd.WriteString(" ")
	}
	sqlCmd.WriteString(" from ")
	sqlCmd.WriteString(t.database)
	sqlCmd.WriteString(".")
	sqlCmd.WriteString(t.superTableName)
	sqlCmd.WriteString(" where ")
	sqlCmd.WriteString(queryWhere)
	sqlCmd.WriteString(" ")
	if sort != 0 {
		if sort == 1 {
			sqlCmd.WriteString("order by ts desc")
		}else {
			sqlCmd.WriteString("order by ts")
		}
		sqlCmd.WriteString(" ")
	}
	sqlCmd.WriteString(" LIMIT ")
	sqlCmd.WriteString(strconv.Itoa(pageSize))
	sqlCmd.WriteString(" OFFSET ")
	sqlCmd.WriteString(strconv.Itoa((pageIndex - 1) * pageSize))
	sqlCmd.WriteString(";")
    sql := sqlCmd.String()
	res, err := t.Execute(sql)
	if err != nil {
		return nil, totalCount, err
	}
	return res, totalCount, err
}